package com.xm.xmds1705083.service.netty;

import com.xm.xm.util.ErrorCode;
import com.xm.xmds1705083.service.model.SocketEntity;
import com.xm.xmds1705083.service.util.CodeUtil;
import com.xm.xmds1705083.service.util.HexCodeUtils;
import com.xm.xmds1705083.service.util.MacUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.swing.text.html.parser.Entity;
import java.io.IOException;
import java.util.List;

/**
 * @Company 杭州新苗网络科技有限公司
 * @Author : loysen
 * @DateTime：2017年4月22日 下午5:53:06
 * @Description : {消息解码类}
 *
 *
 */
public class    ServerSocketEntityDecoder extends ByteToMessageDecoder {

    Logger logger = LoggerFactory.getLogger(ServerSocketEntityDecoder.class);

    // private static final int BUFFER_SIZE = 1024;// 缓存大小
    byte[] recvBuf = null;// 接收消息的缓存
    private final static String start = "FAFA";// 包头标志
    private final static String end = "AFAF";// 结束标志

    int count = 0;// 接收消息的总大小
    byte[] byteMerger = new byte[0];// 接收消息byte数组合并
    int cutCount = 0;// 裁剪值 0:不裁剪 1:裁剪
    boolean deCodeSuccess = true; //
    int recvMsgSize = 0;// byte数组接收消息的大小


    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf bb, List<Object> out) {
        recvMsgSize = bb.readableBytes();
        recvBuf = new byte[recvMsgSize];
        bb.readBytes(recvBuf);
        count = recvMsgSize + count;
        byteMerger = CodeUtil.byteMerger(byteMerger, recvBuf, recvMsgSize);
        if (count < 32 ) {
            return;
        }
        // 判断是否已经读完;判断数据是否完整
        if (count >= 32 ) {
            // byte[]数组转为16进制字符串
            String recvData = CodeUtil.printHexString(byteMerger, count);
            System.out.println("recvMsgSize  :" + recvMsgSize + "  recvBuf :" + recvData);
            recvData = recvData.replace(" ", "");
            // 解析协议
            byteMerger = solveStickPackage(recvData, out, cutCount, deCodeSuccess);

            count = byteMerger.length;
            deCodeSuccess = true;
            cutCount = 0;
        }
        // 清空recvBuf
        recvBuf = null;
    }

    /**
     * @Author loysen
     * @Data_Time 2017年6月16日 上午10:21:23
     * @Description {字符串形式解析包协议}
     * @param data
     * @return
     * @throws IOException
     */
    public byte[] decodeStrData(String data, List<Object> out, int cutCount,  boolean deCodeSuccess) {
        // 协议格式：SocketEntity类
        data =data.substring( data.indexOf(start), data.indexOf(end)+20);

        System.out.println("SocketEntity类:"+data);
        SocketEntity entity = new SocketEntity();
        entity.setStart(data.substring(0,4));
        entity.setEnd( data.substring(data.length() - 20,data.length() -16));
        int len=HexCodeUtils.getShortLE(data, 4);
        int ver=HexCodeUtils.getShortLE( data,8 );
        int cmd=HexCodeUtils.getShortLE( data,12 );
        int ty=HexCodeUtils.getShortLE( data,16 );
        int sq= HexCodeUtils.getIntLE( data, 44);
        int fla= HexCodeUtils.getIntLE( data,52 );

        // 检查包头标志： start
        // minLength = (2+2+2++2+2+2+12+4+4+2+2 )*2 = 64
        if (data.length() > 64 && start.equals(entity.getStart().toUpperCase())
                && end.equals(entity.getEnd().toUpperCase())    ) {
            entity.setLength(Integer.valueOf( len).toString() );
            entity.setVersion(Integer.valueOf( ver ).toString());
            entity.setCmd( Integer.valueOf( cmd ).toString() );
            entity.setType( Integer.valueOf( ty ).toString() );
            entity.setSeq( Integer.valueOf( sq ).toString() );
            entity.setFlag( Integer.valueOf( fla ).toString() );
            entity.setTermid(HexCodeUtils.hexStr2Str(data.substring(20, 44)) );
            entity.setParam(HexCodeUtils.hexStr2Str( data.substring(60,data.length()-20)  ));
            entity.setMac(data.substring(data.length()-16, data.length() ) );
            System.out.println("SocketEntity类:entity----"+entity);
            // 索
            int index = 2 + 2 + Integer.valueOf(entity.getLength()) + 8 ;

            // 判断索引是否超出字符串长度
            if (index <= data.length()) {
                try {
                    byte[] crc16_data = CodeUtil.hexStringToBytes( data.substring( 0, 60 ) + data.substring(60,data.length()-20) + data.substring( data.length() - 20, data.length() - 16) );
                    System.out.println("data1----------"+crc16_data);
                    String data4=HexCodeUtils.byte2HexStr(crc16_data);
                    String data6= data4.replace( " ","" );
                    System.out.println("data----------"+data6);
                    String mac = "19a76825a9aab500";//密钥


                    byte[] dd = MacUtil.calculateANSIX9_9MAC( mac.getBytes(  ), data6.getBytes() );
                    String ddt = HexCodeUtils.byte2HexStr( dd );

                    String crc16 = ddt.replace( " ", "" );
                    crc16 = crc16.substring( 0, 8);
                    System.out.println( "SocketEntity类:mas-----" + crc16 );
                    // CRC校验，判断数据是否完整
                    if (crc16.equals( entity.getMac() )) {
                        // j校验通过，传递Entity
                        out.add( entity );
                        // 裁剪一个完整的包数据
                        // System.out.println("裁剪一个完整包前的data   :"+data);
                        logger.info( "裁剪一个完整包前的data   :" + data );
                        data = data.substring( index, data.length() );
                        // System.out.println("裁剪一个完整包后的data   :" + data);
                        logger.info( "裁剪一个完整包后的data   :" + data );
                        cutCount = 0;
                        // 数据完整并且校验通过
                        logger.info( "数据完整并且校验通过   :" + data );
                        System.out.println( "数据完整并且校验通过   :" + data );
                        deCodeSuccess = true;
                        System.out.println( "第二次裁剪后的data  ：" + "5555555555555555555555555" );
                    } else {
                        // 数据长度足够，但CRC校验不通过
                        deCodeSuccess = false;
                    }
                    }catch(Exception e ){
                        e.printStackTrace();

                    }


            } else {
                // 数据长度不够
                deCodeSuccess = false;
            }
        } else {
            // 数据包标志格式不对
            deCodeSuccess = false;
        }
        // System.out.println("DeCode_Success   :"+DeCode_Success);
        return solveStickPackage(data, out, cutCount, deCodeSuccess);
    }

    /**
     * @Author loysen
     * @Data_Time 2017年4月2日 上午10:21:23
     * @Description {解决粘包，包不完整等问题}
     * @param data
     * @param out
     * @return
     * @throws IOException
     */
    public byte[] solveStickPackage(String data, List<Object> out,
                                      int cutCount, boolean deCodeSuccess) {
         System.out.println("开始解析 包数据： start ....  "+data);
        int headCount = CodeUtil.getContainStrCount(start, data);
        // System.out.println("HEAD_COUNT   :" + HEAD_COUNT);
        // 判断数据长度并且包含包头标志
        if (data.length() > 64 && headCount > 1) {
            data = data.substring(data.indexOf(start) + 4 * cutCount,  data.length());
            cutCount = 1;
            System.out.println("第二次裁剪后的data 1111111 ：" + data);
            return decodeStrData(data, out, cutCount, deCodeSuccess);
        } else if (data.length() > 0 && headCount < 1) {
            // data中没有包头标志，说明不是一个完整包，丢弃
            data = null;
            logger.info("data中没有包头标志，说明不是一个完整包，丢弃data");
            System.out.println("第二次裁剪后的data  ：" +"22222222222222222222222222222");
            // System.out.println("data中没有包头标志，说明不是一个完整包，丢弃data");
            return new byte[0];
        } else if ( headCount > 0 ) {// 临界状态，只有一个包头标志，但数据不全等
            if (data.length() < 64 || !deCodeSuccess) {
                // data中包含包头标志，但数据不完全
                // System.out.println("data中包含包头标志，但数据不完全    data ： " + data);
                logger.info("data中包含包头标志，但数据不完全， data ： " + data);
                System.out.println("第二次裁剪后的data  ：" +"2333333333333333333333");
                return CodeUtil.hexStringToBytes(data);
            } else {
                // data中包含包头标志，但不肯定数据是否完全，不完全时 DeCode_Success标志为：true
                // System.out.println("data中包含包头标志，但不肯定数据是否完全  data :  "+data);
                logger.info("data中包含包头标志，但不肯定数据是否完全  data :  "+data);
                System.out.println("第二次裁剪后的data  ：" +"2444444444444444444");
                return decodeStrData(data, out, cutCount, deCodeSuccess);
            }
        }
        return new byte[0];
    }




}
